/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.tedu.mall.seckill.service.impl;

import cn.tedu.mall.common.pojo.product.vo.SkuStandardVO;
import cn.tedu.mall.common.pojo.seckill.model.SeckillSku;
import cn.tedu.mall.common.pojo.seckill.vo.SeckillSkuVO;
import cn.tedu.mall.product.service.seckill.IForSeckillSkuService;
import cn.tedu.mall.seckill.mapper.SeckillSkuMapper;
import cn.tedu.mall.seckill.service.ISeckillSkuService;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @since 2022-02-23
 */
@Service
public class SeckillSkuServiceImpl implements ISeckillSkuService {
    @DubboReference
    private IForSeckillSkuService dubboSkuService;
    @Autowired
    private SeckillSkuMapper seckillSkuMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<SeckillSkuVO> listSeckillSkus(Long spuId) {
        //先从seckll数据库查询
        List<SeckillSku> seckillSkus = seckillSkuMapper.selectSeckillSkusBySpuId(spuId);
        //准备返回数据
        List<SeckillSkuVO> seckillSkuVOs = new ArrayList<>();
        //解析seckill数据库拿到skuId 挨个封装完整,添加到列表
        for (SeckillSku seckillSku : seckillSkus) {
            SeckillSkuVO seckillSkuVO = null;
            Long skuId = seckillSku.getSkuId();
            //查询缓存是否有数据
            String seckillSkuVOKey = SeckillCacheUtils.getSeckillSkuVOKey(skuId);
            if (redisTemplate.hasKey(seckillSkuVOKey)) {
                seckillSkuVO = (SeckillSkuVO) redisTemplate.boundValueOps(seckillSkuVOKey).get();
            }
            //这时候还是空，说明缓存没有数据
            if (seckillSkuVO == null) {
                //远程调用微服务 获取商品系统返回值
                SkuStandardVO skuStandardVO = dubboSkuService.getById(skuId);
                //给null值的seckillSkuVO生成对象
                seckillSkuVO = new SeckillSkuVO();
                BeanUtils.copyProperties(skuStandardVO, seckillSkuVO);
                //在单独封装 覆盖库存,缺少秒杀价钱,限制数量
                seckillSkuVO.setStock(seckillSku.getSeckillStock());
                seckillSkuVO.setSeckillPrice(seckillSku.getSeckillPrice());
                seckillSkuVO.setSeckillLimit(seckillSku.getSeckillLimit());
                //将数据添加到缓存一份,供后续使用
                redisTemplate.boundValueOps(seckillSkuVOKey).set(seckillSkuVO, 1000 * 60 * 60 * 72 + RandomUtils.nextInt(1000 * 60 * 60 * 5), TimeUnit.MILLISECONDS);
            }
            //到这里seckillSkuVO正常封装数据就不为 空了
            seckillSkuVOs.add(seckillSkuVO);
        }
        return seckillSkuVOs;
    }
}
